"""工具函数模块

提供文件系统操作、视频ID提取、TXT格式处理等通用功能
"""

import os
import re
import json
from typing import Dict, List, Any, Optional


def ensure_directory(directory_path: str) -> str:
    """确保目录存在，如果不存在则创建
    
    Args:
        directory_path: 目录路径
    
    Returns:
        创建或确保存在的目录路径
    """
    try:
        os.makedirs(directory_path, exist_ok=True)
        return directory_path
    except Exception as e:
        print(f"创建目录失败 {directory_path}: {str(e)}")
        raise


def read_file(file_path: str, encoding: str = 'utf-8') -> Optional[str]:
    """读取文件内容
    
    Args:
        file_path: 文件路径
        encoding: 文件编码
    
    Returns:
        文件内容
    
    Raises:
        FileNotFoundError: 当文件不存在时
    """
    if not os.path.exists(file_path):
        raise FileNotFoundError(f"文件不存在: {file_path}")
    try:
        with open(file_path, 'r', encoding=encoding) as f:
            return f.read()
    except IOError as e:
        print(f"读取文件失败 {file_path}: {str(e)}")
        raise


def write_file(file_path: str, content: str, encoding: str = 'utf-8') -> bool:
    """写入文件内容
    
    Args:
        file_path: 文件路径
        content: 要写入的内容
        encoding: 文件编码
    
    Returns:
        是否写入成功
    """
    try:
        # 确保目录存在
        directory = os.path.dirname(file_path)
        if directory:
            ensure_directory(directory)
        
        with open(file_path, 'w', encoding=encoding) as f:
            f.write(content)
        return True
    except IOError as e:
        print(f"写入文件失败 {file_path}: {str(e)}")
        return False


def extract_video_id(filename: str) -> Optional[str]:
    """从文件名或URL中提取视频ID
    
    Args:
        filename: 文件名或URL
    
    Returns:
        提取的视频ID，如果无法提取则返回None
    """
    # 处理URL格式
    url_patterns = [
        r'https?://[^/]+/video/([a-zA-Z0-9_-]+)',  # 标准视频URL
        r'https?://v\.douyin\.com/([a-zA-Z0-9_-]+)/?',  # 短链接格式
    ]
    
    for pattern in url_patterns:
        match = re.search(pattern, filename)
        if match:
            return match.group(1)
    
    # 移除路径，只保留文件名
    filename = os.path.basename(filename)
    
    # 常见的视频ID格式模式，增强匹配能力
    file_patterns = [
        r'^(\d+)\.[a-zA-Z0-9]+$',  # 纯数字ID加任何扩展名
        r'^(\d+)_.*\.[a-zA-Z0-9]+$',  # 数字ID开头，后跟下划线和其他内容
        r'^.*_(\d+)\.[a-zA-Z0-9]+$',  # 其他内容后跟下划线和数字ID
        r'^video_(\d+)\.[a-zA-Z0-9]+$',  # video_开头，后跟数字ID
        r'^[a-zA-Z0-9_-]+$',  # 纯字母数字下划线连字符格式
    ]
    
    for pattern in file_patterns:
        match = re.match(pattern, filename, re.IGNORECASE)
        if match:
            # 如果模式有捕获组，返回捕获的内容
            if match.groups():
                return match.group(1)
            # 否则返回整个匹配
            return match.group(0)
    
    # 如果没有匹配到特定格式，返回不带扩展名的文件名作为ID
    name_without_ext = os.path.splitext(filename)[0]
    return name_without_ext if name_without_ext else None


def validate_video_id(video_id: str) -> bool:
    """验证视频ID格式是否有效
    
    Args:
        video_id: 视频ID
    
    Returns:
        ID是否有效
    """
    # 简单验证：不为空且长度合理（排除太短的ID）
    if not video_id or len(video_id) == 0 or len(video_id) < 6 or len(video_id) > 100:
        return False
    
    # 检查是否包含非法字符（只允许字母、数字、下划线和连字符）
    if not re.match(r'^[a-zA-Z0-9_-]+$', video_id):
        return False
    
    return True


def format_result_to_txt(result: Dict[str, Any], output_order: List[str] = None) -> str:
    """将分析结果格式化为TXT格式
    
    Args:
        result: 分析结果字典
        output_order: 输出字段的顺序列表，如果为None则使用字典的键顺序
    
    Returns:
        格式化后的TXT字符串
    """
    lines = []
    
    # 如果没有指定输出顺序，使用字典的键
    if output_order is None:
        output_order = list(result.keys())
    
    for field in output_order:
        if field in result:
            value = result[field]
            # 如果是字典，转换为字符串
            if isinstance(value, dict):
                value = json.dumps(value, ensure_ascii=False, indent=2)
            # 如果是列表，转换为字符串
            elif isinstance(value, list):
                value = ', '.join(str(v) for v in value)
            # 如果是None，转换为空字符串
            elif value is None:
                value = ''
            
            lines.append(f"{field}: {value}")
    
    return '\n'.join(lines)


def parse_txt_result(txt_content: str) -> Dict[str, Any]:
    """从TXT格式解析分析结果
    
    Args:
        txt_content: TXT格式的内容
    
    Returns:
        解析后的结果字典
    """
    result = {}
    lines = txt_content.strip().split('\n')
    
    for line in lines:
        # 使用第一个冒号作为分隔符
        if ': ' in line:
            key, value = line.split(': ', 1)
            # 尝试解析JSON格式的值
            if value.startswith('{') and value.endswith('}'):
                try:
                    value = json.loads(value)
                except json.JSONDecodeError:
                    pass  # 如果解析失败，保持字符串格式
            result[key] = value
    
    return result


def get_video_files(directory: str, recursive: bool = False) -> List[str]:
    """获取目录下所有视频文件
    
    Args:
        directory: 要搜索的目录
        recursive: 是否递归搜索子目录
    
    Returns:
        视频文件路径列表
    """
    video_extensions = {'.mp4', '.avi', '.mov', '.mkv', '.wmv'}
    video_files = []
    
    if not os.path.exists(directory):
        return video_files
    
    if recursive:
        for root, dirs, files in os.walk(directory):
            for filename in files:
                ext = os.path.splitext(filename)[1].lower()
                if ext in video_extensions:
                    video_files.append(os.path.join(root, filename))
    else:
        for filename in os.listdir(directory):
            file_path = os.path.join(directory, filename)
            if os.path.isfile(file_path):
                ext = os.path.splitext(filename)[1].lower()
                if ext in video_extensions:
                    video_files.append(file_path)
    
    return video_files


def get_relative_data_path(base_dir: str = None) -> str:
    """获取相对于项目根目录的data目录路径
    
    Args:
        base_dir: 相对路径，如果提供则将其与项目根目录连接
    
    Returns:
        合并后的路径
    """
    # 获取当前文件所在目录
    current_dir = os.path.dirname(os.path.abspath(__file__))
    # 获取项目根目录（假设当前目录在src下）
    project_root = os.path.dirname(current_dir)
    
    if base_dir is None:
        # 如果没有提供base_dir，返回data目录的路径
        data_path = os.path.join(project_root, "data")
        return data_path
    else:
        # 如果提供了base_dir，将其与项目根目录连接
        return os.path.join(project_root, base_dir)